package plantshop.tests;

import static org.junit.Assert.*;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;

import plantshop.controller.moves.CustomerBuyMove;
import plantshop.controller.moves.CustomerFindGoalMove;
import plantshop.controller.moves.CustomerWalkMove;
import plantshop.controller.moves.DeleteCustomerMove;
import plantshop.controller.moves.Move;
import plantshop.model.Characteristics;
import plantshop.model.CollisionDetector;
import plantshop.model.Customer;
import plantshop.model.Display;
import plantshop.model.Location;
import plantshop.model.Store;
import plantshop.model.plants.Aster;
import plantshop.model.plants.BurningBush;
import plantshop.model.plants.CommonMilkweed;
import plantshop.model.plants.EasternRedCedar;
import plantshop.model.plants.Plant;

public class CustomerTests
{
	static Store store;
	@BeforeClass
	public static void setUpBeforeClass() throws Exception
	{
		Customer.setEntrance(new Location(0, 0));
		Customer.setExit(new Location(1920, 1080));
		Customer.setXScale(1);
		Customer.setYScale(1);
		
		store = new Store(100, 1, 1);
		store.getFront().removeAll(store.getFront());
		Display d = new Display(4, 500, 500, true, 1, 1); //BR = (670, 670)
		store.getFront().add(d);
		store.setTopLeft(new Location(0, 0));
		store.setBottomRight(new Location(1920, 1080));
		
		CollisionDetector.setXScale(1);
		CollisionDetector.setYScale(1);
		CollisionDetector.setStore(store);
	}

	@AfterClass
	public static void tearDownAfterClass() throws Exception
	{
	}

	@Before
	public void setUp() throws Exception
	{
	}

	@After
	public void tearDown() throws Exception
	{
	}

	@Test
	public void testMakeCustomer()
	{
		Customer c;
		boolean charsFailed = false;
		boolean typeFailed = false;
		for(int i = 0; i < 100; i++)
		{
			c = Customer.makeCustomer();
			List<Integer> chars = new ArrayList<Integer>();
			for(int j : c.getDesiredPlant().getChars())
				chars.add(j);
			charsFailed = Collections.max(chars) > 10 || Collections.min(chars) < 5 || charsFailed;
			typeFailed = c.getType() > 2 || c.getType() < 0 || typeFailed;
		}
		assertEquals(false, charsFailed);
		assertEquals(false, typeFailed);
	}
	
	@Test
	public void testSetLoc()
	{
		Customer c = Customer.makeCustomer();
		Location loc = c.getLoc();
		c.setLoc(null);
		assertEquals(loc, c.getLoc());
		
		c = Customer.makeCustomer();
		c.setLoc(new Location(500, 500));
		assertEquals(new Location(500, 500), c.getLoc());
	}

	@Test
	public void testWantsToBuy()
	{
		Customer c = Customer.makeCustomer();
		assertFalse(c.wantsToBuy(null));
		
		c = Customer.makeCustomer(1, new Characteristics(5, 5, 10, 10, 10));
		Plant p = new Aster();
		assertFalse(c.wantsToBuy(p));
		
		c = Customer.makeCustomer(1, new Characteristics(8, 9, 5, 5, 7));
		assertTrue(c.wantsToBuy(p));
		
		c = Customer.makeCustomer(1, new Characteristics(5, 5, 5, 5, 5));
		assertTrue(c.wantsToBuy(p));
		
		p.markTaken();
		assertFalse(c.wantsToBuy(p));
	}

	@Test
	public void testGetNextMove()
	{
		Customer c = Customer.makeCustomer(1, new Characteristics(5, 5, 5, 5, 5));
		Move m = c.getNextMove();
		assertTrue(m instanceof CustomerWalkMove);
		
		m = c.getNextMove();
		assertTrue(m instanceof CustomerFindGoalMove);
		
		m = c.getNextMove();
		assertTrue(m instanceof CustomerWalkMove);
		
		c = Customer.makeCustomer(1, new Characteristics(5, 5, 5, 5, 10));
		c.setLeaveTrue();
		m = c.getNextMove();
		assertTrue(m instanceof CustomerWalkMove);
		
		c.setLoc(Customer.EXIT);
		m = c.getNextMove();
		assertTrue(m instanceof DeleteCustomerMove);
		
		c = Customer.makeCustomer(1, new Characteristics(5, 5, 5, 5, 10));
		c.setGoalLoc(new Location(500, 500));
		m = c.getNextMove();
		assertTrue(m instanceof CustomerWalkMove);
		
		c.setLoc(new Location(500, 500));
		c.setGoalPlant(new BurningBush());
		m = c.getNextMove();
		assertTrue(m instanceof CustomerBuyMove);
		
		c = Customer.makeCustomer(1, new Characteristics(5, 5, 5, 5, 10));
		m = c.getNextMove();
		assertTrue(m instanceof CustomerWalkMove);
	}
	
	
	@Test
	public void testGetWalkTowardsMove()
	{
		//Display TL = (500,500) BR = (670,670)
		//Customer WIDTH = 125, HEIGHT = 50
		Customer c1 = Customer.makeCustomer();
		Customer c2 = Customer.makeCustomer();
		store.addCustomer(c1);
		store.addCustomer(c2);
		CustomerWalkMove m;
		
		//Test walk left normal
		c1.setLoc(new Location(700, 700));
		m = (CustomerWalkMove)c1.getWalkTowardsMove(new Location(699, 700));
		assertEquals(-1, m.getX());
		assertEquals(0, m.getY());
		
		//Test walk up normal
		c1.setLoc(new Location(700, 700));
		m = (CustomerWalkMove)c1.getWalkTowardsMove(new Location(700, 699));
		assertEquals(0, m.getX());
		assertEquals(-1, m.getY());
		
		//Test walk right normal
		c1.setLoc(new Location(700, 700));
		m = (CustomerWalkMove)c1.getWalkTowardsMove(new Location(701, 700));
		assertEquals(1, m.getX());
		assertEquals(0, m.getY());
		
		//Test walk down normal
		c1.setLoc(new Location(700, 700));
		m = (CustomerWalkMove)c1.getWalkTowardsMove(new Location(700, 701));
		assertEquals(0, m.getX());
		assertEquals(1, m.getY());
		
		//Test walk left customer
		c1.setLoc(new Location(700, 700));
		c2.setLoc(new Location(574, 700));
		m = (CustomerWalkMove)c1.getWalkTowardsMove(new Location(699, 700));
		assertEquals(0, m.getX());
		assertEquals(-1, m.getY());
		
		//Test walk up customer
		c1.setLoc(new Location(700, 700));
		c2.setLoc(new Location(700, 649));
		m = (CustomerWalkMove)c1.getWalkTowardsMove(new Location(700, 699));
		assertEquals(1, m.getX());
		assertEquals(0, m.getY());
		
		//Test walk right customer
		c1.setLoc(new Location(700, 700));
		c2.setLoc(new Location(826, 700));
		m = (CustomerWalkMove)c1.getWalkTowardsMove(new Location(701, 700));
		assertEquals(0, m.getX());
		assertEquals(1, m.getY());
		
		//Test walk down customer
		c1.setLoc(new Location(700, 700));
		c2.setLoc(new Location(700, 751));
		m = (CustomerWalkMove)c1.getWalkTowardsMove(new Location(700, 701));
		assertEquals(-1, m.getX());
		assertEquals(0, m.getY());
		
		//Test walk left display
		c1.setLoc(new Location(671, 670));
		m = (CustomerWalkMove)c1.getWalkTowardsMove(new Location(670, 670));
		assertEquals(0, m.getX());
		assertEquals(1, m.getY());
		
		//Test walk up display
		c1.setStuck(false);
		c1.setLoc(new Location(670, 671));
		m = (CustomerWalkMove)c1.getWalkTowardsMove(new Location(670, 670));
		assertEquals(-1, m.getX());
		assertEquals(0, m.getY());
		
		//Test walk right display
		c1.setStuck(false);
		c1.setLoc(new Location(374, 670));
		m = (CustomerWalkMove)c1.getWalkTowardsMove(new Location(375, 670));
		assertEquals(0, m.getX());
		assertEquals(-1, m.getY());
		
		//Test walk down display
		c1.setStuck(false);
		c1.setLoc(new Location(670, 449));
		m = (CustomerWalkMove)c1.getWalkTowardsMove(new Location(670, 450));
		assertEquals(1, m.getX());
		assertEquals(0, m.getY());
		
		//Test unstuck left
		c1.setStuck(false);
		c1.setLoc(new Location(671, 670));
		c1.getWalkTowardsMove(new Location(200, 670));
		c1.setLoc(new Location(671, 671));
		m = (CustomerWalkMove)c1.getWalkTowardsMove(new Location(200, 670));
		assertEquals(-1, m.getX());
		assertEquals(0, m.getY());
		
		//Test unstuck up
		c1.setStuck(false);
		c1.setLoc(new Location(375, 671));
		c1.getWalkTowardsMove(new Location(375, 200));
		c1.setLoc(new Location(374, 671));
		m = (CustomerWalkMove)c1.getWalkTowardsMove(new Location(375, 200));
		assertEquals(0, m.getX());
		assertEquals(-1, m.getY());
		
		//Test unstuck right
		c1.setStuck(false);
		c1.setLoc(new Location(374, 670));
		c1.getWalkTowardsMove(new Location(671, 670));
		c1.setLoc(new Location(374, 449));
		m = (CustomerWalkMove)c1.getWalkTowardsMove(new Location(671, 670));
		assertEquals(1, m.getX());
		assertEquals(0, m.getY());
		
		//Test unstuck down
		c1.setStuck(false);
		c1.setLoc(new Location(670, 449));
		c1.getWalkTowardsMove(new Location(670, 671));
		c1.setLoc(new Location(671, 449));
		m = (CustomerWalkMove)c1.getWalkTowardsMove(new Location(670, 671));
		assertEquals(0, m.getX());
		assertEquals(1, m.getY());
		
		//Test don't move
		c1.setStuck(false);
		c1.setLoc(new Location(500, 500));
		m = (CustomerWalkMove)c1.getWalkTowardsMove(new Location(670, 670));
		assertEquals(0, m.getX());
		assertEquals(0, m.getY());
	}
	
	@Test
	public void testGetWanderMove()
	{
		Customer c = Customer.makeCustomer();
		c.setLoc(new Location(700, 700));
		CustomerWalkMove lastMove = (CustomerWalkMove) c.getWanderMove();
		while(lastMove.getX() == 0 && lastMove.getY() == 0)
			lastMove = (CustomerWalkMove) c.getWanderMove();
		if(lastMove.getX() < 0 || lastMove.getY() < 0)
			c.setLoc(new Location(670 + lastMove.getX(), 670 + lastMove.getY()));
		else
			c.setLoc(new Location(375 - lastMove.getX(), 475 - lastMove.getY()));
		CustomerWalkMove m = (CustomerWalkMove) c.getWanderMove();
		
//		System.out.println(lastMove.getX() + " " + lastMove.getY());
//		System.out.println(m.getX() + " " + m.getY());
		
		assertTrue(m instanceof CustomerWalkMove);
		assertTrue(lastMove.getX() != m.getX() || lastMove.getY() != m.getY());
	}

	@Test
	public void testWalk()
	{
		Customer c1 = Customer.makeCustomer();
		c1.setLoc(new Location(500, 500));
		c1.walk(new Location(1000, 1000));
		
		assertEquals(new Location(1000, 1000), c1.getLoc());
		assertEquals(new Location(1125, 1050), c1.getBottomRight());
	}

	@Test
	public void testDeleteCustomer()
	{
		Customer c = Customer.makeCustomer();
		Move m = c.deleteCustomer();
		assertTrue(m instanceof DeleteCustomerMove);
	}

	@Test
	public void testCompareTo()
	{
		Customer c1 = Customer.makeCustomer();
		Customer c2 = Customer.makeCustomer();
		Customer c3 = Customer.makeCustomer();
		c1.setLoc(new Location(500, 500));
		c2.setLoc(new Location(500, 400));
		c3.setLoc(new Location(400, 500));
		
		assertTrue(c1.compareTo(c2) > 0);
		assertTrue(c2.compareTo(c1) < 0);
		assertTrue(c1.compareTo(c3) == 0);
		
	}
	
	@Test
	public void testIsLeaving()
	{
		Customer c = Customer.makeCustomer();
		assertFalse(c.isLeaving());
		
		c = Customer.makeCustomer(1, new Characteristics(5, 5, 5, 5, 10));
		c.setGoalLoc(new Location(500, 500));
		c.setLoc(new Location(500, 500));
		c.setGoalPlant(new EasternRedCedar());
		c.getNextMove();
		
		assertTrue(c.isLeaving());
	}
	
	@Test
	public void testGetSetGoalPlant()
	{
		Customer c = Customer.makeCustomer();
		Plant p = new CommonMilkweed();
		c.setGoalPlant(p);
		assertEquals(p, c.getGoalPlant());
	}
	
	@Test
	public void testSetLeaveTrue()
	{
		Customer c = Customer.makeCustomer();
		c.setLeaveTrue();
		assertTrue(c.isLeaving());
	}
	
	@Test
	public void testGetDesiredPlant()
	{
		Customer c = Customer.makeCustomer(1, new Characteristics(5, 6, 7, 8, 9));
		assertEquals(new Characteristics(5, 6, 7, 8, 9), c.getDesiredPlant());
	}
	
	@Test
	public void testGetType()
	{
		Customer c = Customer.makeCustomer(1, new Characteristics(5, 6, 7, 8, 9));
		assertEquals(1, c.getType());
	}
	
	@Test
	public void testGetSetMoneyNum()
	{
		Customer c = Customer.makeCustomer();
		c.setMoneyNum(476);
		assertEquals(476, c.getMoneyNum());
	}
	
	@Test
	public void testGetSetDisplayMoneySign()
	{
		Customer c = Customer.makeCustomer();
		c.setDisplayMoneySign(134);
		assertEquals(134, c.getDisplayMoneySign());
	}
	
	@Test
	public void testGetSetEmotion()
	{
		Customer c = Customer.makeCustomer();
		c.setEmotion(5);
		assertEquals(5, c.getEmotion());
	}
	
	@Test
	public void testGetSetStuck()
	{
		Customer c = Customer.makeCustomer();
		c.setStuck(true);
		assertTrue(c.getStuck());
	}
}
